﻿using System.Runtime.CompilerServices;
using System.Runtime.Loader;

namespace Futuret.Core.Extensions;

/// <summary>
///     Author: Riva
///     Date: 2023/7/11 14:02
///     Description: 反射扩展类
/// </summary>
public static class ReflectionExtension
{
    public static bool IsNotAbstractClass(this Type type, bool publicOnly)
    {
        if (type.IsSpecialName)
            return false;

        if (type is { IsClass: true, IsAbstract: false })
        {
            if (type.HasAttribute<CompilerGeneratedAttribute>())
                return false;

            if (publicOnly)
                return type.IsPublic || type.IsNestedPublic;

            return true;
        }

        return false;
    }

    public static bool HasAttribute(this Type type, Type attributeType)
    {
        return type.IsDefined(attributeType, true);
    }

    /// <summary>
    ///     判断是否有T特性
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <returns></returns>
    public static bool HasAttribute<T>(this Type type) where T : Attribute
    {
        return type.HasAttribute(typeof(T));
    }

    /// <summary>
    ///     判断是否有T特性
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="type"></param>
    /// <param name="predicate"></param>
    /// <returns></returns>
    public static bool HasAttribute<T>(this Type type, Func<T, bool> predicate) where T : Attribute
    {
        return type.GetCustomAttributes<T>(true).Any(predicate);
    }

    /// <summary>
    ///     根据程序集名称获取运行时程序集
    /// </summary>
    /// <param name="assemblyName"></param>
    /// <returns></returns>
    internal static Assembly GetAssembly(string assemblyName)
    {
        // 加载程序集
        return AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName));
    }

    /// <summary>
    ///     获取入口程序集
    /// </summary>
    /// <returns></returns>
    internal static Assembly? GetEntryAssembly()
    {
        return Assembly.GetEntryAssembly();
    }

    /// <summary>
    ///     根据路径加载程序集
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    internal static Assembly? LoadAssembly(string path)
    {
        return !File.Exists(path) ? default : Assembly.LoadFrom(path);
    }

    /// <summary>
    ///     通过流加载程序集
    /// </summary>
    /// <param name="assembly"></param>
    /// <returns></returns>
    internal static Assembly LoadAssembly(MemoryStream assembly)
    {
        return Assembly.Load(assembly.ToArray());
    }

    /// <summary>
    ///     根据程序集名称、类型完整限定名获取运行时类型
    /// </summary>
    /// <param name="assemblyName"></param>
    /// <param name="typeFullName"></param>
    /// <returns></returns>
    internal static Type? GetType(string assemblyName, string typeFullName)
    {
        return GetAssembly(assemblyName).GetType(typeFullName);
    }

    /// <summary>
    ///     根据程序集和类型完全限定名获取运行时类型
    /// </summary>
    /// <param name="assembly"></param>
    /// <param name="typeFullName"></param>
    /// <returns></returns>
    internal static Type? GetType(Assembly assembly, string typeFullName)
    {
        return assembly.GetType(typeFullName);
    }

    /// <summary>
    ///     根据程序集和类型完全限定名获取运行时类型
    /// </summary>
    /// <param name="assembly"></param>
    /// <param name="typeFullName"></param>
    /// <returns></returns>
    internal static Type? GetType(MemoryStream assembly, string typeFullName)
    {
        return LoadAssembly(assembly).GetType(typeFullName);
    }

    /// <summary>
    ///     获取程序集名称
    /// </summary>
    /// <param name="assembly"></param>
    /// <returns></returns>
    internal static string? GetAssemblyName(Assembly assembly)
    {
        return assembly.GetName().Name;
    }

    /// <summary>
    ///     获取程序集名称
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    internal static string? GetAssemblyName(Type type)
    {
        return GetAssemblyName(type.GetTypeInfo());
    }

    /// <summary>
    ///     获取程序集名称
    /// </summary>
    /// <param name="typeInfo"></param>
    /// <returns></returns>
    internal static string? GetAssemblyName(TypeInfo typeInfo)
    {
        return GetAssemblyName(typeInfo.Assembly);
    }

    /// <summary>
    ///     加载程序集类型，支持格式：程序集;网站类型命名空间
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    internal static Type? GetStringType(string str)
    {
        var typeDefinitions = str.Split(";");
        return GetType(typeDefinitions[0], typeDefinitions[1]);
    }
}